import cv2
import tkinter as tk  # 用于获取屏幕分辨率
import numpy as np

# 使用 tkinter 获取屏幕分辨率
root = tk.Tk()
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
root.destroy()

# 读取图片文件
image = cv2.imread(r"E:\Desktop\TI2024\TI2024_E_python\test_image\ChessBord004.jpg")

# 获取图像的大小
original_height, original_width = image.shape[:2]

# 指定正方形区域的宽度
square_size = 1000  # 你可以根据需要调整

# 计算图像中心位置
center_y = original_height // 2
center_x = original_width // 2

# 计算正方形区域的左上角和右下角坐标
top_left_y = max(center_y - square_size // 2, 0)
top_left_x = max(center_x - square_size // 2, 0)
bottom_right_y = min(center_y + square_size // 2, original_height)
bottom_right_x = min(center_x + square_size // 2, original_width)

# 确保正方形区域的大小
if bottom_right_y - top_left_y != square_size or bottom_right_x - top_left_x != square_size:
    print("警告：截取的区域大小不符，请检查图像大小和正方形区域设置。")

# 截取图像中心的正方形区域
square_image = image[top_left_y:bottom_right_y, top_left_x:bottom_right_x]

# 将正方形图像转换为灰度图像
gray_image = cv2.cvtColor(square_image, cv2.COLOR_BGR2GRAY)

# 进行中值滤波以去噪
median_filtered_image = cv2.medianBlur(gray_image, 5)  # 使用 5x5 的滤波器

# 对灰度图像进行二值化处理
_, binary_image = cv2.threshold(median_filtered_image, 30, 255, cv2.THRESH_BINARY)

# 进行高斯模糊
Gaussian_image = cv2.GaussianBlur(binary_image, (7, 7), 0)

# 提取图像边缘
edges = cv2.Canny(Gaussian_image, 100, 200)
# 使用 Hough 变换检测直线
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=50, minLineLength=100, maxLineGap=100)
lines_image = square_image.copy()
# 将图像变为纯黑
lines_image[:] = 0  # 或者可以使用 lines_image = np.zeros_like(square_image)

height, width = lines_image.shape[:2]

for index, line in enumerate(lines):
    x1, y1, x2, y2 = line[0]

    # 计算直线的斜率和截距
    if x2 - x1 != 0:  # 避免除以零
        slope = (y2 - y1) / (x2 - x1)
        intercept = y1 - slope * x1

        # 计算延长线的两个端点
        # 计算延长线的y坐标
        y1_extended = int(slope * 0 + intercept)  # 当x=0时的y
        y2_extended = int(slope * width + intercept)  # 当x=width时的y

        # 计算延长线的x坐标
        x1_extended = int((0 - intercept) / slope)  # 当y=0时的x
        x2_extended = int((height - intercept) / slope)  # 当y=height时的x

        # 画延长线（使用边界点）
        cv2.line(lines_image, (0, y1_extended), (width - 1, y2_extended), (255, 255, 255), 20)  # 线宽为2
        cv2.line(lines_image, (x1_extended, 0), (x2_extended, height - 1), (255, 255, 255), 20)  # 线宽为2
    else:
        # 处理垂直线
        cv2.line(lines_image, (x1, 0), (x1, height - 1), (255, 255, 255), 20)  # 线宽为2

# 进行高斯模糊
Gaussian_image_handle = cv2.GaussianBlur(lines_image, (7, 7), 0)

# 提取图像边缘
edges_handle = cv2.Canny(Gaussian_image_handle, 100, 200)

# 找到轮廓
contours, _ = cv2.findContours(edges_handle, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 创建一个黑色图像用于绘制轮廓
contours_image = np.zeros_like(square_image)
# 遍历每个轮廓并绘制
for contour in contours:
    cv2.drawContours(contours_image, [contour], -1, (0, 0, 255), 1)  # 红色轮廓，线宽为2

rectangles_image = square_image.copy()
# 将图像变为纯黑
# rectangles_image[:] = 0  # 或者可以使用 lines_image = np.zeros_like(square_image)

# 定义重合阈值（可根据需要调整）
overlap_threshold = 50  # 像素值，表示中心点之间的最小距离
# 存储有效轮廓的中心点
valid_centers = []
# 设置面积阈值
max_area_threshold = 100000  # 根据需要调整此值
min_area_threshold = 500  # 根据需要调整此值

# 遍历每个轮廓并绘制
for index, contour in enumerate(contours):
    # 近似轮廓以获取多边形
    epsilon = 0.02 * cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(contour, epsilon, True)

    # 计算轮廓面积
    area = cv2.contourArea(contour)

    # 检查轮廓面积是否满足阈值
    if area < min_area_threshold or area > max_area_threshold:
        continue  # 如果面积小于阈值，则跳过该轮廓

    # 计算矩形的中心点
    M = cv2.moments(approx)
    if M["m00"] != 0:  # 防止除以零
        cx = int(M["m10"] / M["m00"])
        cy = int(M["m01"] / M["m00"])
        center = (cx, cy)
    else:
        continue  # 如果没有有效的轮廓，跳过

    # 检查中心点是否与已有中心点重合
    is_overlapping = False
    for (prev_cx, prev_cy) in valid_centers:
        distance = np.sqrt((cx - prev_cx) ** 2 + (cy - prev_cy) ** 2)
        if distance < overlap_threshold:
            is_overlapping = True
            break

    if not is_overlapping:
        # 如果不重合，则绘制轮廓和标注
        cv2.polylines(rectangles_image, [approx], isClosed=True, color=(0, 255, 0), thickness=1)  # 绿色矩形边框
        valid_centers.append(center)  # 添加有效中心点

        # 在中心点处打点
        cv2.circle(rectangles_image, center, 5, (0, 0, 255), -1)  # 红色实心圆，半径为5

        # 在中心点处标注序号和坐标
        cv2.putText(rectangles_image, f"{len(valid_centers)}: ({cx}, {cy})", (cx, cy),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)  # 红色文字，字体大小为0.5


# 定义移动窗口到中心的函数
def move_window_to_center(window_name, img):
    height, width = img.shape[:2]
    x_position = (screen_width - width) // 2
    y_position = (screen_height - height) // 2
    cv2.moveWindow(window_name, x_position, y_position)


# 显示原始图像并移动窗口
cv2.imshow('Image', image)
move_window_to_center('Image', image)

# 显示正方形图像并移动窗口
cv2.imshow('Square Image', square_image)
move_window_to_center('Square Image', square_image)

# 显示灰度图像并移动窗口
cv2.imshow('Gray Image', gray_image)
move_window_to_center('Gray Image', gray_image)

# 显示高斯模糊图像并移动窗口
cv2.imshow('median_filtered_image', median_filtered_image)
move_window_to_center('median_filtered_image', median_filtered_image)

# 显示二值化图像并移动窗口
cv2.imshow('binary_image', binary_image)
move_window_to_center('binary_image', binary_image)

# 显示高斯模糊图像并移动窗口
cv2.imshow('Gaussian_image', Gaussian_image)
move_window_to_center('Gaussian_image', Gaussian_image)

# 显示图像边缘
cv2.imshow('edges', edges)
move_window_to_center('edges', edges)

# 显示获取的直线
cv2.imshow('lines_image', lines_image)
move_window_to_center('lines_image', lines_image)

# 显示获取的直线
cv2.imshow('Gaussian_image_handle', Gaussian_image_handle)
move_window_to_center('Gaussian_image_handle', Gaussian_image_handle)

# 显示处理后的图像边缘
cv2.imshow('edges_handle', edges_handle)
move_window_to_center('edges_handle', edges_handle)

# 显示获取的轮廓
cv2.imshow('contours_image', contours_image)
move_window_to_center('contours_image', contours_image)

# 显示获取的矩形
cv2.imshow('rectangles_image', rectangles_image)
move_window_to_center('rectangles_image', rectangles_image)

# 等待用户按下任意键关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
